#pragma once
#include <zGraphicsConfig.hpp>
#include "FBO.hpp"
#include <Image\Image.hpp>
#include <Graphics\OpenGLTools.hpp>

namespace zzz{
class ZGRAPHICS_CLASS Renderbuffer {
public:
  Renderbuffer(GLenum internalFormat);
  Renderbuffer(GLenum internalFormat, int width, int height);
  ~Renderbuffer();

  inline void Bind()
  {
    GLBindRenderBuffer::Set(GetID());
  }

  inline void Unbind()
  {
    GLBindRenderBuffer::Restore();
  }

  inline GLuint GetID()
  {
    if (!IsValid()) {
      glGenRenderbuffersEXT(1, &buf_);
      CHECK_GL_ERROR();
      ZCHECK_NOT_ZERO(buf_);
    }
    return buf_;
  }
  void Create(int width, int height);
  void Create(GLenum internalFormat, int width, int height);
  bool IsValid() {
    bool valid=(glIsRenderbuffer(buf_)==GL_TRUE);
    CHECK_GL_ERROR()
      return valid;
  }
  template<typename T>
  bool ImageToRenderBuffer(const Image<T> &img);
  template<typename T>
  bool RenderBufferToImage(Image<T> &img);

private:
  GLuint buf_;
  int width_,height_;
  int internal_format_;
  inline static GLint GetMaxSize();
};

// It is not correct, I don't which buffer should be set to readbuffer/drawbuffer
template<typename T> 
bool Renderbuffer::ImageToRenderBuffer(const Image<T> &img)
{
  GLvoid *data=(GLvoid *)img.Data();
  Set(internalFormat, img.Cols(), img.Rows());
  Bind();
  GLDrawBuffer::Set(GL_RENDERBUFFER);
  glMatrixMode(GL_MODELVIEW);
  glPushMatrix();
  glMatrixMode(GL_PROJECTION);
  glPushMatrix();
  GLRasterPos::Set(0,0,0,1);
  glDrawPixels(width_, height_, img.Format_, img.Type_, data);
  GLRasterPos::Restore();
  glPopMatrix();
  glMatrixMode(GL_MODELVIEW);
  glPopMatrix();
  GLDrawBuffer::Restore();
  CHECK_GL_ERROR();
  return true;
}

template<typename T> 
bool Renderbuffer::RenderBufferToImage(Image<T> &img)
{
  if (!IsValid()) return false;
  Bind();
  GLReadBuffer::Set(GL_RENDERBUFFER);
  img.SetSize(height_,width_);
  GLvoid *data=(GLvoid *)img.Data();
  glReadPixels(0, 0, width_, height_, img.Format_, img.Type_, data);
  GLReadBuffer::Restore();
  Unbind();
  CHECK_GL_ERROR()
  return true;
}

}